unit DIrr.Particle;

{$I DIrr.inc}

interface

uses
  DIrr.Config, DIrr.Types, DIrr.Color, DIrr.IO, DIrr.Structs,
  DIrr.Vector3D, DIrr.Dimension2D, DIrr.AabBox3D;

type
  //! A particle emitter for using with particle systems.
  (** A Particle emitter emitts new particles into a particle system.*)
  TParticleEmitter = class(TAttributeExchangingObject)
  public
    //! Prepares an array with new particles to emitt into the system
    (** \param now Current time.
    \param timeSinceLastCall Time elapsed since last call, in milliseconds.
    \param outArray Pointer which will point to the array with the new
    particles to add into the system.
    \return Amount of new particles in the array. Can be 0. *)
    function Emitt(NowTime: U32; TimeSinceLastCall: U32;
      var OutArrayPtr: PParticle): S32; virtual; stdcall; abstract;

    //! Set direction the emitter emits particles
    procedure SetDirection(const NewDirection: TVector3DF); virtual; stdcall; abstract;

    //! Set minimum number of particles the emitter emits per second
    procedure SetMinParticlesPerSecond(MinPPS: U32); virtual; stdcall; abstract;

    //! Set maximum number of particles the emitter emits per second
    procedure SetMaxParticlesPerSecond(MaxPPS: U32); virtual; stdcall; abstract;

    //! Set minimum starting color for particles
    procedure SetMinStartColor(const Color: TIrrColor); virtual; stdcall; abstract;

    //! Set maximum starting color for particles
    procedure SetMaxStartColor(const Color: TIrrColor); virtual; stdcall; abstract;

    //! Set the maximum starting size for particles
    procedure SetMaxStartSize(const Size: TDimension2DF); virtual; stdcall; abstract;

    //! Set the minimum starting size for particles
    procedure SetMinStartSize(const Size: TDimension2DF); virtual; stdcall; abstract;

    //! Set the minimum particle life-time in milliseconds
    procedure SetMinLifeTime(LifeTimeMin: U32); virtual; stdcall; abstract;

    //! Set the maximum particle life-time in milliseconds
    procedure SetMaxLifeTime(LifeTimeMax: U32); virtual; stdcall; abstract;

    //!	Set maximal random derivation from the direction
    procedure SetMaxAngleDegrees(MaxAngleDegrees: S32); virtual; stdcall; abstract;

    //! Get direction the emitter emits particles
    function GetDirection: PVector3DF; virtual; stdcall; abstract;

    //! Get the minimum number of particles the emitter emits per second
    function GetMinParticlesPerSecond: U32; virtual; stdcall; abstract;

    //! Get the maximum number of particles the emitter emits per second
    function GetMaxParticlesPerSecond: U32; virtual; stdcall; abstract;

    //! Get the minimum starting color for particles
    function GetMinStartColor: PIrrColor; virtual; stdcall; abstract;

    //! Get the maximum starting color for particles
    function GetMaxStartColor: PIrrColor; virtual; stdcall; abstract;

    //! Get the maximum starting size for particles
    function GetMaxStartSize: PDimension2DF; virtual; stdcall; abstract;

    //! Get the minimum starting size for particles
    function GetMinStartSize: PDimension2DF; virtual; stdcall; abstract;

    //! Get the minimum particle life-time in milliseconds
    function GetMinLifeTime: U32; virtual; stdcall; abstract;

    //! Get the maximum particle life-time in milliseconds
    function GetMaxLifeTime: U32; virtual; stdcall; abstract;

    //!	Get maximal random derivation from the direction
    function GetMaxAngleDegrees: S32; virtual; stdcall; abstract;

    //! Get emitter type
    function GetType: E_PARTICLE_EMITTER_TYPE; virtual; stdcall;
  end;

  TParticlePointEmitter = class(TParticleEmitter)
  end;

  TParticleBoxEmitter = class(TParticleEmitter)
  public
    //! Set the box shape
    procedure SetBox(const Box: TAabBox3DF); virtual; stdcall; abstract;

    //! Get the box shape set
    function GetBox: PAabBox3DF; virtual; stdcall; abstract;

    //! Get emitter type
    function GetType: E_PARTICLE_EMITTER_TYPE; override;
  end;

  TParticleCylinderEmitter = class(TParticleEmitter)
  public
    //! Set the center of the radius for the cylinder, at one end of the cylinder
    procedure SetCenter(const Center: TVector3DF); virtual; stdcall; abstract;

    //! Set the normal of the cylinder
    procedure SetNormal(const Normal: TVector3DF); virtual; stdcall; abstract;

    //! Set the radius of the cylinder
    procedure SetRadius(Radius: F32); virtual; stdcall; abstract;

    //! Set the length of the cylinder
    procedure SetLength(Len: F32); virtual; stdcall; abstract;

    //! Set whether or not to draw points inside the cylinder
    procedure SetOutlineOnly(OutlineOnly: Boolean = True); virtual; stdcall; abstract;

    //! Get the center of the cylinder
    function GetCenter: PVector3DF; virtual; stdcall; abstract;

    //! Get the normal of the cylinder
    function GetNormal: PVector3DF; virtual; stdcall; abstract;

    //! Get the radius of the cylinder
    function GetRadius: F32; virtual; stdcall; abstract;

    //! Get the center of the cylinder
    function GetLength: F32; virtual; stdcall; abstract;

    //! Get whether or not to draw points inside the cylinder
    function GetOutlineOnly: Boolean; virtual; stdcall; abstract;

    //! Get emitter type
    function GetType: E_PARTICLE_EMITTER_TYPE; override;
  end;


  TParticleRingEmitter = class(TParticleEmitter)
  public
    //! Set the center of the ring
    procedure SetCenter(const Center: TVector3DF); virtual; stdcall; abstract;

    //! Set the radius of the ring
    procedure SetRadius(Radius: F32); virtual; stdcall; abstract;

    //! Set the thickness of the ring
    procedure SetRingThickness(RingThickness: F32); virtual; stdcall; abstract;

    //! Get the center of the ring
    function GetCenter: PVector3DF; virtual; stdcall; abstract;

    //! Get the radius of the ring
    function GetRadius: F32; virtual; stdcall; abstract;

    //! Get the thickness of the ring
    function GetRingThickness: F32; virtual; stdcall; abstract;

    //! Get emitter type
    function GetType: E_PARTICLE_EMITTER_TYPE; override;
  end;

  TParticleSphereEmitter = class(TParticleEmitter)
  public
    //! Set the center of the sphere for particle emissions
    procedure SetCenter(const Center: TVector3DF); virtual; stdcall; abstract;

    //! Set the radius of the sphere for particle emissions
    procedure SetRadius(Radius: F32); virtual; stdcall; abstract;

    //! Get the center of the sphere for particle emissions
    function GetCenter: PVector3DF; virtual; stdcall; abstract;

    //! Get the radius of the sphere for particle emissions
    function GetRadius: F32; virtual; stdcall; abstract;

    //! Get emitter type
    function GetType: E_PARTICLE_EMITTER_TYPE; override;
  end;


  TParticleAffector = class(TAttributeExchangingObject)
  protected
    FEnabled: Boolean;
  public
    constructor Create;
  public
    //! Affects an array of particles.
    (** \param now Current time. (Same as ITimer::getTime() would return)
    \param particlearray Array of particles.
    \param count Amount of particles in array. *)
    procedure Affect(NowTime: U32; ParticleArrayPtr: PParticle; Count: U32); virtual; stdcall; abstract;

    //! Sets whether or not the affector is currently enabled.
    procedure SetEnabled(Value: Boolean); virtual; stdcall;

    //! Gets whether or not the affector is currently enabled.
    function GetEnabled: Boolean; virtual; stdcall;

    //! Get emitter type
    function GetType: E_PARTICLE_AFFECTOR_TYPE; virtual; stdcall; abstract;
  public
    property Enabled: Boolean read GetEnabled write SetEnabled;
  end;

  TParticleFadeOutAffector = class(TParticleAffector)
  public
    //! Sets the targetColor, i.e. the color the particles will interpolate to over time.
    procedure SetTargetColor(const TargetColor: TIrrColor); virtual; stdcall; abstract;

    //! Sets the time in milliseconds it takes for each particle to fade out (minimal 1 ms)
    procedure SetFadeOutTime(FadeOutTime: U32); virtual; stdcall; abstract;

    //! Gets the targetColor, i.e. the color the particles will interpolate to over time.
    function GetTargetColor: PIrrColor; virtual; stdcall; abstract;

    //! Gets the time in milliseconds it takes for each particle to fade out.
    function GetFadeOutTime: U32; virtual; stdcall; abstract;

    //! Get emitter type
    function GetType: E_PARTICLE_AFFECTOR_TYPE; override;
  end;

  TParticleGravityAffector = class(TParticleAffector)
  public
    //! Set the time in milliseconds when the gravity force is totally lost
    (** At that point the particle does not move any more. *)
    procedure SetTimeForceLost(TimeForceLost: F32); virtual; stdcall; abstract;

    //! Set the direction and force of gravity in all 3 dimensions.
    procedure SetGravity(const Gravity: TVector3DF); virtual; stdcall; abstract;

    //! Get the time in milliseconds when the gravity force is totally lost
    function GetTimeForceLost: F32; virtual; stdcall; abstract;

    //! Get the direction and force of gravity.
    function GetGravity: PVector3DF; virtual; stdcall; abstract;

    //! Get emitter type
    function GetType: E_PARTICLE_AFFECTOR_TYPE; override;
  end;

  TParticleRotationAffector = class(TParticleAffector)
  public
    //! Set the point that particles will rotate around
    procedure SetPivotPoint(const Point: TVector3DF); virtual; stdcall; abstract;

    //! Set the speed in degrees per second in all 3 dimensions
    procedure SetSpeed(const Speed: TVector3DF); virtual; stdcall; abstract;

    //! Get the point that particles are attracted to
    function GetPivotPoint: PVector3DF; virtual; stdcall; abstract;

    //! Get the speed in degrees per second in all 3 dimensions
    function GetSpeed: PVector3DF; virtual; stdcall; abstract;

    //! Get emitter type
    function GetType: E_PARTICLE_AFFECTOR_TYPE; override;
  end;

  TParticleAttractionAffector = class(TParticleAffector)
  public
    //! Set the point that particles will attract to
    procedure SetPoint(const Point: TVector3DF); virtual; stdcall; abstract;

    //! Set whether or not the particles are attracting or detracting
    procedure SetAttract(Attract: Boolean); virtual; stdcall; abstract;

    //! Set whether or not this will affect particles in the X direction
    procedure SetAffectX(Affect: Boolean); virtual; stdcall; abstract;

    //! Set whether or not this will affect particles in the Y direction
    procedure SetAffectY(Affect: Boolean); virtual; stdcall; abstract;

    //! Set whether or not this will affect particles in the Z direction
    procedure SetAffectZ(Affect: Boolean); virtual; stdcall; abstract;

    //! Get the point that particles are attracted to
    function GetPoint: PVector3DF; virtual; stdcall; abstract;

    //! Get whether or not the particles are attracting or detracting
    function GetAttract: Boolean; virtual; stdcall; abstract;

    //! Get whether or not the particles X position are affected
    function GetAffectX: Boolean; virtual; stdcall; abstract;

    //! Get whether or not the particles Y position are affected
    function GetAffectY: Boolean; virtual; stdcall; abstract;

    //! Get whether or not the particles Z position are affected
    function GetAffectZ: Boolean; virtual; stdcall; abstract;

    //! Get emitter type
    function GetType: E_PARTICLE_AFFECTOR_TYPE; override;
  public
    property AffectX: Boolean read GetAffectX write SetAffectX;
    property AffectY: Boolean read GetAffectY write SetAffectY;
    property AffectZ: Boolean read GetAffectZ write SetAffectZ;
  end;

implementation

{ TParticleEmitter }

function TParticleEmitter.GetType: E_PARTICLE_EMITTER_TYPE;
begin
  Result := EPET_POINT;
end;

{ TParticleAffector }

constructor TParticleAffector.Create;
begin
  FEnabled := True;
end;

function TParticleAffector.GetEnabled: Boolean;
begin
  Result := FEnabled;
end;

procedure TParticleAffector.SetEnabled(Value: Boolean);
begin
  FEnabled := Value;
end;

{ TParticleBoxEmitter }

function TParticleBoxEmitter.GetType: E_PARTICLE_EMITTER_TYPE;
begin
  Result := EPET_BOX;
end;

{ TParticleCylinderEmitter }

function TParticleCylinderEmitter.GetType: E_PARTICLE_EMITTER_TYPE;
begin
  Result := EPET_CYLINDER;
end;

{ TParticleRingEmitter }

function TParticleRingEmitter.GetType: E_PARTICLE_EMITTER_TYPE;
begin
  Result := EPET_RING;
end;

{ TParticleSphereEmitter }

function TParticleSphereEmitter.GetType: E_PARTICLE_EMITTER_TYPE;
begin
  Result := EPET_SPHERE;
end;

{ TParticleFadeOutAffector }

function TParticleFadeOutAffector.GetType: E_PARTICLE_AFFECTOR_TYPE;
begin
  Result := EPAT_FADE_OUT;
end;

{ TParticleGravityAffector }

function TParticleGravityAffector.GetType: E_PARTICLE_AFFECTOR_TYPE;
begin
  Result := EPAT_GRAVITY;
end;

{ TParticleRotationAffector }

function TParticleRotationAffector.GetType: E_PARTICLE_AFFECTOR_TYPE;
begin
  Result := EPAT_ROTATE;
end;

{ TParticleAttractionAffector }

function TParticleAttractionAffector.GetType: E_PARTICLE_AFFECTOR_TYPE;
begin
  Result := EPAT_ATTRACT;
end;

end.
